<template>
	<view class="">
		<!-- #ifdef H5 -->
		<view class="loading-box" v-show="showLoading">
			<view id="loading3">
				<view class="demo3"></view>
				<view class="demo3"></view>
				<view class="demo3"></view>
				<view class="demo3"></view>
				<view class="demo3"></view>
				<view class="demo3"></view>
				<view class="demo3"></view>
				<view class="demo3"></view>
			</view>
		</view>
		<view id="container"></view>
		<!-- #endif -->
	</view>
</template>
<script>
	// #ifdef H5
	import * as THREE from "three";
	import {
		OrbitControls
	} from "three/examples/jsm/controls/OrbitControls.js";
	import {
		DRACOLoader
	} from "three/examples/jsm/loaders/DRACOLoader.js";

	import {
		GLTFLoader
	} from "three/examples/jsm/loaders/GLTFLoader.js";

	export default {
		props: {
			modelUrl: {
				type: String,
				default: ''
			}
		},
		data() {
			return {
				mesh: null,
				camera: null,
				scene: null,
				renderer: null,
				controls: null,
				isMove: true,
				x: null,
				y: null,
				z: null,
				animateId: null,
				modelUrlData: '',
				showLoading: false,
				isGlb: false,
				theSave: null
			};
		},
		onLoad() {},
		mounted() {
			this.modelUrlData = this.modelUrl
			if (this.modelUrlData) {
				this.showLoading = true;
				this.init(this.modelUrlData, false)
			}
		},
		methods: {
			// 初始化
			init(url, getPic = true) {
				this.$nextTick(() => {
					this.createScene(); // 创建场景
					if (url.indexOf(".glb") > -1) {
						// glb
						this.isGlb = true;
						this.loadGLTFSTL(url, getPic);
					} else {
						this.isGlb = false;
						console.log('-----url', url)
						this.loadSTL(url, getPic); // 加载STL模型'
					}
				});
			},
			// 创建场景
			createScene() {
				this.scene = new THREE.Scene();
			},
			//加载glb模型
			loadGLTFSTL(url, getPic) {
				let _this = this;
				//创建相机
				_this.createCameraGltf();
				const dracoLoader = new DRACOLoader();
				dracoLoader.setDecoderPath(
					"../../static/draco/"
				); // use a full url pat

				const gltf = new GLTFLoader();
				gltf.setDRACOLoader(dracoLoader);

				gltf.load(url, function(gltf) {
					gltf.scene.traverse(function(child) {
						if (child.isMesh) {
							child.geometry.center(); // center here
							// child.frustumCulled = false;
							// //模型阴影
							// child.castShadow = true;
							// child.receiveShadow = true;
							// 自己发光
							// child.material.emissive = child.material.color;
							// child.material.emissiveMap = child.material.map;
						}
					});
					let bbox = new THREE.Box3().setFromObject(gltf.scene);
					let cent = bbox.getCenter(new THREE.Vector3());
					let size = bbox.getSize(new THREE.Vector3());
					let maxAxis = Math.max(size.x, size.y, size.z);
					gltf.scene.scale.multiplyScalar(0.8 / maxAxis);
					bbox.setFromObject(gltf.scene);
					bbox.getCenter(cent);
					bbox.getSize(size);
					//Reposition to 0,halfY,0
					gltf.scene.position.copy(cent).multiplyScalar(-1);
					gltf.scene.position.y += size.y * 0.1;
					_this.rotationGltf(gltf.scene)
					_this.scene.add(gltf.scene);
					// 关闭 模型loading 状态 ??
					// _this.$emit("modelloding");
				});
				_this.createLight(); // 创建光源
				_this.createRender(); // 创建渲染器
				// 控件对象
				_this.createControls();
				_this.renderGltf(); // 渲染
				this.showLoading = false;
			},
			// 加载STL模型
			loadSTL(url, getPic) {
				console.log(url)
				const THIS = this;

				var loader;
				loader = new DRACOLoader();
				loader.setDecoderPath(
					"../../static/draco/");
				loader.setDecoderConfig({
					type: "js",
				});
				loader.load(url, (geometry) => {
					geometry.center();
					// 创建材质
					const material = new THREE.MeshStandardMaterial();
					// const material = new THREE.MeshStandardMaterial({ color: '#3636ff' });
					this.mesh = new THREE.Mesh(geometry, material);
					this.mesh.scale.set(1, 1, 1);
					let bbox = new THREE.Box3().setFromObject(this.mesh);
					this.x = bbox.max.x - bbox.min.x;
					this.y = bbox.max.y - bbox.min.y;
					this.z = bbox.max.z - bbox.min.z;
					this.mesh.position.set(
						-(bbox.max.x + bbox.min.x) / 2,
						-(bbox.max.y + bbox.min.y) / 2,
						-(bbox.max.z + bbox.min.z) / 2
					);
					this.scene.add(this.mesh);
					this.createCamera(""); // 创建相机
					this.createLight(); // 创建光源
					this.createRender(); // 创建渲染器
					this.createControls(); // 创建控件对象
					this.render(); // 渲染
					this.showLoading = false;
				});
			},
			// 创建光源
			createLight() {
				// 环境光
				const ambientLight = new THREE.AmbientLight(0xffffff, 0.1); // 创建环境光
				this.scene.add(ambientLight); // 将环境光添加到场景

				let directLight = new THREE.DirectionalLight(0xffffff, 0.5); // 创建聚光灯
				directLight.position.set(200, 300, 200);
				directLight.castShadow = true;
				directLight.shadow.mapSize.width = 1024;
				directLight.shadow.mapSize.height = 1024;
				directLight.shadow.camera.left = -80; // 15
				directLight.shadow.camera.right = 80;
				directLight.shadow.camera.top = 80;
				directLight.shadow.camera.bottom = -80;
				directLight.shadow.camera.far = 1000; //
				directLight.shadow.bias = 0.00001; //
				directLight.shadow.camera.updateProjectionMatrix();
				this.camera.add(directLight); //

				let pointLight = new THREE.PointLight(0xffffff, 0.3);
				pointLight.position.set(-300, -100, 50);
				this.camera.add(pointLight);
			},
			// 创建相机
			createCamera(size) {
				const element = document.getElementById("container");
				const width = element.clientWidth; // 窗口宽度
				const height = element.clientHeight; // 窗口高度
				const k = width / height; // 窗口宽高比

				this.camera = new THREE.PerspectiveCamera(45, k, 0.1, 100000000);
				// 获取相机对象，PerspectiveCamera表示一种透视照相机；
				//第一个参数表示这个相机的广角，就是能看到的角度；
				//第二个参数表示相机获取到的视野要呈现的长宽比，一般用画布的长宽比就可以呈现原场景比例；
				//第三个参数与第四个参数分别表示远近切面，意思是这个（1~1000）距离之外的场景就不再显示了
				let x = this.x;
				let y = this.y;
				let z = this.z;
				if (y / x >= k) {
					let h = y;
					let Fov = (this.camera.fov * Math.PI) / 180;
					let m = h / (2 * Math.tan(Fov * 0.5));
					this.camera.position.y = m + z / 2;
					this.camera.position.z = m + z / 2;
					this.camera.position.x = 0;
				} else {
					let w = x;
					let h = w * k;
					let Fov = (this.camera.fov * Math.PI) / 180;
					let m = h / (2 * Math.tan(Fov * 0.5));
					this.camera.position.y = m + z / 2;
					this.camera.position.z = m + z / 2;
					this.camera.position.x = 0;
				}
				this.scene.add(this.camera);

				// 添加辅助XYZ线
				// var axis = new THREE.AxesHelper(1000);
				// this.scene.add(axis);
			},
			//创建相机 gltf
			createCameraGltf() {
				const element = document.getElementById("container");
				const width = element.clientWidth; // 窗口宽度
				const height = element.clientHeight; // 窗口高度
				const k = width / height; // 窗口宽高比
				this.camera = new THREE.PerspectiveCamera(45, k, 0.1, 100000000);
				this.camera.position.set(-0.75, 0.7, 1.25);
				this.scene.add(this.camera);
			},
			// 创建渲染器
			createRender() {
				const element = document.getElementById("container");
				this.renderer = new THREE.WebGLRenderer({
					preserveDrawingBuffer: true,
					antialias: true,
					alpha: true,
				});
				this.renderer.setSize(element.clientWidth, element.clientHeight); // 设置渲染区域尺寸
				this.renderer.shadowMap.enabled = true; // 显示阴影
				this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
				let col = "#f3f3f3";
				this.renderer.setClearColor(col, 1); // 设置背景颜色
				if (this.isGlb) {
					this.renderer.setPixelRatio(window.devicePixelRatio);
					this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
					this.renderer.toneMappingExposure = 1;
					this.renderer.outputEncoding = THREE.sRGBEncoding; // 加了这个 glb 比较亮
				}
				element.appendChild(this.renderer.domElement);
			},
			changeTheme(color) {
				this.renderer.setClearColor(color, 1); // 设置背景颜色
			},
			render() {
				if (this.mesh.rotation.y <= Math.PI && this.isMove) {
					this.mesh.rotation.y = this.mesh.rotation.y + 0.005;
					// this.mesh.rotation.z = this.mesh.rotation.z + 0.01;
					// this.mesh.rotation.x = this.mesh.rotation.x + 0.01;
				}

				this.renderer.render(this.scene, this.camera);
				this.animateId = requestAnimationFrame(this.render); // id 用于移除渲染时用
			},
			// glb 旋转
			rotationGltf(model = null) {
				if (model) {
					this.theSave = model
				}
				if (this.theSave && this.theSave.rotation.y <= Math.PI && this.isMove) {
					this.theSave.rotation.y = this.theSave.rotation.y + 0.005;
				}
			},
			renderGltf() {
				this.rotationGltf()
				this.renderer.render(this.scene, this.camera);
				this.animateId = requestAnimationFrame(this.renderGltf); // id 用于移除渲染时用
			},
			// 创建控件对象
			createControls() {
				this.controls = new OrbitControls(this.camera, this.renderer.domElement);
				document
					.getElementById("container")
					.addEventListener("click", this.stopRotation);
			},
			stopRotation() {
				// console.log('stopRotation')
				this.isMove = false;
			},
			dataURItoBlob(dataURI) {
				// convert base64/URLEncoded data component to raw binary data held in a string
				var byteString;
				if (dataURI.split(",")[0].indexOf("base64") >= 0)
					byteString = atob(dataURI.split(",")[1]);
				else byteString = unescape(dataURI.split(",")[1]);

				// separate out the mime component
				var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];

				// write the bytes of the string to a typed array
				var ia = new Uint8Array(byteString.length);
				for (var i = 0; i < byteString.length; i++) {
					ia[i] = byteString.charCodeAt(i);
				}

				return new Blob([ia], {
					type: mimeString,
				});
			},
			removeCanvas() {
				let dome = document.getElementById("container"); //拿到画布父元素
				if (dome && dome.children[0]) {
					dome.removeChild(dome.children[0]); //销毁canvas
				}
				cancelAnimationFrame(this.animateId);
			},
		},
		beforeDestroy() {},
		destroyed() {
			console.log('destroyed')
			this.removeCanvas();
		},
	};

	// #endif
</script>
<!-- #ifdef H5 -->
<style lang="scss" scoped>
	#container {
		position: absolute;
		width: 100%;
		height: 100%;
		z-index: 10;
	}

	.loading-box {
		position: absolute;
		width: 100%;
		height: 100%;
		z-index: 11;
		background-color: #fff;
		display: flex;
		align-items: center;
		justify-content: center;
	}

	#loading3 {
		position: relative;
		width: 50px;
		height: 50px;
	}

	.demo3 {
		width: 4px;
		height: 4px;
		border-radius: 2px;
		background: #3636ff;
		position: absolute;
		animation: demo3 linear 0.8s infinite;
		-webkit-animation: demo3 linear 0.8s infinite;
	}

	.demo3:nth-child(1) {
		left: 24px;
		top: 2px;
		animation-delay: 0s;
	}

	.demo3:nth-child(2) {
		left: 40px;
		top: 8px;
		animation-delay: 0.1s;
	}

	.demo3:nth-child(3) {
		left: 47px;
		top: 24px;
		animation-delay: 0.1s;
	}

	.demo3:nth-child(4) {
		left: 40px;
		top: 40px;
		animation-delay: 0.2s;
	}

	.demo3:nth-child(5) {
		left: 24px;
		top: 47px;
		animation-delay: 0.4s;
	}

	.demo3:nth-child(6) {
		left: 8px;
		top: 40px;
		animation-delay: 0.5s;
	}

	.demo3:nth-child(7) {
		left: 2px;
		top: 24px;
		animation-delay: 0.6s;
	}

	.demo3:nth-child(8) {
		left: 8px;
		top: 8px;
		animation-delay: 0.7s;
	}

	@keyframes demo3 {

		0%,
		40%,
		100% {
			transform: scale(1);
		}

		20% {
			transform: scale(3);
		}
	}

	@-webkit-keyframes demo3 {

		0%,
		40%,
		100% {
			transform: scale(1);
		}

		20% {
			transform: scale(3);
		}
	}
</style>
<!-- #endif -->
